<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="chrome=1">
    
    <title>【深入浅出jQuery】源码浅析--整体架构 | Coco ’s blog</title>
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
    
    <meta name="author" content="Coco">
    
    
    <meta name="keywords" content="jQuery源码分析, jQuery源码, jQuery框架, jQuery架构">
    <meta name="description" content="最近一直在研读 jQuery 源码，初看源码一头雾水毫无头绪，真正静下心来细看写的真是精妙，让你感叹代码之美。其结构明晰，高内聚、低耦合，兼具优秀的性能与便利的扩展性，在浏览器的兼容性（功能缺陷、渐进增强）优雅的处理能力以及 Ajax 等方面周到而强大的定制功能无不令人惊叹。">
<meta property="og:type" content="article">
<meta property="og:title" content="【深入浅出jQuery】源码浅析--整体架构 | Coco ’s blog">
<meta property="og:url" content="http://sbco.cc/2016/03/14/jQ1/index.html">
<meta property="og:site_name" content="Coco ’s blog">
<meta property="og:description" content="最近一直在研读 jQuery 源码，初看源码一头雾水毫无头绪，真正静下心来细看写的真是精妙，让你感叹代码之美。其结构明晰，高内聚、低耦合，兼具优秀的性能与便利的扩展性，在浏览器的兼容性（功能缺陷、渐进增强）优雅的处理能力以及 Ajax 等方面周到而强大的定制功能无不令人惊叹。">
<meta property="og:image" content="http://images2015.cnblogs.com/blog/608782/201603/608782-20160311094843022-2127919395.png">
<meta property="og:image" content="http://images2015.cnblogs.com/blog/608782/201603/608782-20160314191813506-188474195.jpg">
<meta property="og:image" content="http://images2015.cnblogs.com/blog/608782/201603/608782-20160314210036021-1888207934.jpg">
<meta property="og:updated_time" content="2016-06-03T10:08:28.899Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="【深入浅出jQuery】源码浅析--整体架构 | Coco ’s blog">
<meta name="twitter:description" content="最近一直在研读 jQuery 源码，初看源码一头雾水毫无头绪，真正静下心来细看写的真是精妙，让你感叹代码之美。其结构明晰，高内聚、低耦合，兼具优秀的性能与便利的扩展性，在浏览器的兼容性（功能缺陷、渐进增强）优雅的处理能力以及 Ajax 等方面周到而强大的定制功能无不令人惊叹。">
<meta name="twitter:image" content="http://images2015.cnblogs.com/blog/608782/201603/608782-20160311094843022-2127919395.png">
    
    <link rel="icon" type="image/x-icon" href="/favicon.png">
    <link rel="stylesheet" href="/css/uno.css">
    <link rel="stylesheet" href="/css/highlight.css">
    <link rel="stylesheet" href="/css/archive.css">
    <link rel="stylesheet" href="/css/china-social-icon.css">
</head>
<body>
    <span class="mobile btn-mobile-menu">
      <i class="icon icon-list btn-mobile-menu__icon"></i>
      <i class="icon icon-x-circle btn-mobile-close__icon hidden"></i>
    </span>
    
<header class="panel-cover panel-cover--collapsed">

  <div class="panel-main">
    <div class="panel-main__inner panel-inverted">
    <div class="panel-main__content">
        
        <img src="/images/logo.png" alt="Coco ’s blog logo" class="panel-cover__logo logo" title="Click Me!!!"/>
        
        <h1 class="panel-cover__title panel-title"><a href="/" title="link to homepage">Coco ’s blog</a></h1>
        <hr class="panel-cover__divider" />
        
        <p class="panel-cover__description">
          少年不知愁滋味 为赋新词强说愁
        </p>
        <hr class="panel-cover__divider panel-cover__divider--secondary" />
        
        <div class="navigation-wrapper">
          <nav class="cover-navigation cover-navigation--primary">
            <ul class="navigation">
              
                
                <li class="navigation__item"><a href="/#blog" title="" class="blog-button">首页</a></li>
              
                
                <li class="navigation__item"><a href="/about/html/" title="" class="">关于</a></li>
              
                
                <li class="navigation__item"><a href="/archive" title="" class="">归档</a></li>
              
              <a target="_blank" href="https://github.com/chokcoco"><li class='navigation__item github' title="To my Github"></li></a>
              <a target="_blank" href="http://www.cnblogs.com/coco1s/"> <li class='navigation__item'><div class='navigation__item blog' title="To my cnblogs"></div></li></a>
            </ul>
          </nav>
          <!-- ----------------------------
To add a new social icon simply duplicate one of the list items from below
and change the class in the <i> tag to match the desired social network
and then add your link to the <a>. Here is a full list of social network
classes that you can use:
    icon-social-500px
    icon-social-behance
    icon-social-delicious
    icon-social-designer-news
    icon-social-deviant-art
    icon-social-digg
    icon-social-dribbble
    icon-social-facebook
    icon-social-flickr
    icon-social-forrst
    icon-social-foursquare
    icon-social-github
    icon-social-google-plus
    icon-social-hi5
    icon-social-instagram
    icon-social-lastfm
    icon-social-linkedin
    icon-social-medium
    icon-social-myspace
    icon-social-path
    icon-social-pinterest
    icon-social-rdio
    icon-social-reddit
    icon-social-skype
    icon-social-spotify
    icon-social-stack-overflow
    icon-social-steam
    icon-social-stumbleupon
    icon-social-treehouse
    icon-social-tumblr
    icon-social-twitter
    icon-social-vimeo
    icon-social-xbox
    icon-social-yelp
    icon-social-youtube
    icon-social-zerply
    icon-mail
-------------------------------->
<!-- add social info here -->


        </div>
      </div>
    </div>
    <div class="panel-cover--overlay"></div>
  </div>
</header>

    <div class="content-wrapper">
      <div class="content-wrapper__inner entry">
        
<article class="post-container post-container--single">
  <header class="post-header">
    <h1 class="post-title">【深入浅出jQuery】源码浅析--整体架构</h1>
    
    <div class="post-meta">
      <time datetime="2016-03-14" class="post-meta__date date">2016-03-14</time>
      <span id="busuanzi_container_page_pv">
        • 阅读量（<span id="busuanzi_value_page_pv"></span>）
      </span>
      <span class="post-meta__tags tags">
          
          
             &#8226; 标签:
            <font class="tags">
              <a class="tags-link" href="/tags/jQuery源码分析/">jQuery源码分析</a>
            </font>
          
      </span>

    </div>
    
  </header>

  <section id="post-content" class="article-content post">
    <p>最近一直在研读 jQuery 源码，初看源码一头雾水毫无头绪，真正静下心来细看写的真是精妙，让你感叹代码之美。</p><p>其结构明晰，高内聚、低耦合，兼具优秀的性能与便利的扩展性，在浏览器的兼容性（功能缺陷、渐进增强）优雅的处理能力以及 Ajax 等方面周到而强大的定制功能无不令人惊叹。<a id="more"></a></p><p>另外，阅读源码让我接触到了大量底层的知识。对原生JS 、框架设计、代码优化有了全新的认识，接下来将会写一系列关于 jQuery 解析的文章。</p><p>我在 github 上关于 jQuery 源码的全文注解，感兴趣的可以围观一下。 <a href="https://github.com/chokcoco/jQuery-" target="_blank" rel="external">jQuery v1.10.2 源码注解 </a>。</p><p>系列第二篇： <a href="http://www.cnblogs.com/coco1s/p/5303041.html" target="_blank" rel="external">【深入浅出jQuery】源码浅析2–奇技淫巧</a></p><p>网上已经有很多解读 jQuery 源码的文章了，作为系列开篇的第一篇，思前想去起了个【深入浅出jQuery】的标题，资历尚浅，无法对 jQuery 分析的头头是道，但是 jQuery 源码当中确实有着大量巧妙的设计，不同层次水平的阅读者都能有收获，所以打算厚着脸皮将自己从中学到的一些知识点共享出来。打算从整体及分支，分章节剖析。本篇主要讲 jQuery 的整体架构及一些前期准备，先来看看 jQuery 的整体结构：</p><h2 id="整体架构"><a href="#整体架构" class="headerlink" title="整体架构"></a>整体架构</h2><p><img src="http://images2015.cnblogs.com/blog/608782/201603/608782-20160311094843022-2127919395.png" alt=""></p><p>不同于 jQuery 代码各个模块细节实现的晦涩难懂，jQuery 整体框架的结构十分清晰，按代码行文大致分为如上图所示的模块。</p><p>初看 jQuery 源码可能很容易一头雾水，因为 9000 行的代码感觉没有尽头，所以了解作者的行文思路十分重要。</p><p>整体而言，我觉得 jQuery 采用的是总–分的结构，虽然 JavaScript 有着作用域的提升机制，但是 9000 多行的代码为了相互的关联性，并不代表所有的变量都要定义在最顶部。在 jQuery 中，只有全局都会用到的变量、正则表达式定义在了代码最开头，而每个模块一开始，又会定义一些只在本模块会使用到的变量、正则、方法等。所以在一开始的阅读的过程中会有很多看不懂其作用的变量，正则，方法。</p><p>所以，我觉得阅读源码很重要的一点是，摒弃面向过程的思维方式，不要刻意去追求从上至下每一句都要在一开始弄明白。很有可能一开始你在一个奇怪的方法或者变量处卡壳了，很想知道这个方法或变量的作用，然而可能它要到几千行处才被调用到。如果去追求这种逐字逐句弄清楚的方式，很有可能在碰壁几次之后阅读的积极性大受打击。</p><p>道理说了很多，接来下进入真正的正文，对 jQurey 的一些前期准备，小的细节进行分析：</p><h2 id="闭包结构"><a href="#闭包结构" class="headerlink" title="闭包结构"></a>闭包结构</h2><figure class="highlight javascript"><table><tr><td class="gutter"><pre>
          <span class="line">1</span>
          <br>
          <span class="line">2</span>
          <br>
          <span class="line">3</span>
          <br>
          <span class="line">4</span>
          <br>
          <span class="line">5</span>
          <br>
          <span class="line">6</span>
          <br>
          <span class="line">7</span>
          <br>
        </pre></td><td class="code"><pre>
          <span class="line">
            <span class="comment">// 用一个函数域包起来，就是所谓的沙箱</span>
          </span>
          <br>
          <span class="line">
            <span class="comment">// 在这里边 var 定义的变量，属于这个函数域内的局部变量，避免污染全局</span>
          </span>
          <br>
          <span class="line">
            <span class="comment">// 把当前沙箱需要的外部变量通过函数参数引入进来</span>
          </span>
          <br>
          <span class="line">
            <span class="comment">// 只要保证参数对内提供的接口的一致性，你还可以随意替换传进来的这个参数</span>
          </span>
          <br>
          <span class="line">(
            <span class="function">
              <span class="keyword">function</span>(
              <span class="params">window, undefined</span>) </span>&#123;</span>
          <br>
          <span class="line">
            <span class="comment">// jQuery 代码</span>
          </span>
          <br>
          <span class="line">&#125;)(
            <span class="built_in">window</span>);</span>
          <br>
        </pre></td></tr></table></figure><p>jQuery 具体的实现，都被包含在了一个立即执行函数构造的闭包里面，为了不污染全局作用域，只在后面暴露 $ 和 jQuery 这 2 个变量给外界，尽量的避开变量冲突。常用的还有另一种写法：<br></p><figure class="highlight javascript"><table><tr><td class="gutter"><pre>
            <span class="line">1</span>
            <br>
            <span class="line">2</span>
            <br>
            <span class="line">3</span>
            <br>
          </pre></td><td class="code"><pre>
            <span class="line">(
              <span class="function">
                <span class="keyword">function</span>(
                <span class="params">window</span>) </span>&#123;</span>
            <br>
            <span class="line">
              <span class="comment">// JS代码</span>
            </span>
            <br>
            <span class="line">&#125;)(
              <span class="built_in">window</span>,
              <span class="literal">undefined</span>);</span>
            <br>
          </pre></td></tr></table></figure><p></p><p>比较推崇的的第一种写法，也就是 jQuery 的写法。二者有何不同呢，当我们的代码运行在更早期的环境当中（pre-ES5，eg. Internet Explorer 8），undefined 仅是一个变量且它的值是可以被覆盖的。意味着你可以做这样的操作：<br></p><figure class="highlight javascript"><table><tr><td class="gutter"><pre>
            <span class="line">1</span>
            <br>
            <span class="line">2</span>
            <br>
          </pre></td><td class="code"><pre>
            <span class="line">
              <span class="literal">undefined</span> =
              <span class="number">42</span>
            </span>
            <br>
            <span class="line">
              <span class="built_in">console</span>.log(
              <span class="literal">undefined</span>)
              <span class="comment">// 42</span>
            </span>
            <br>
          </pre></td></tr></table></figure><p></p><p>当使用第一种方式，可以确保你需要的 undefined 确实就是 undefined。</p><p>另外不得不提出的是，jQuery 在这里有一个针对压缩优化细节，使用第一种方式，在代码压缩的时候，window 和 undefined 都可以压缩为 1 个字母并且确保它们就是 window 和 undefined。<br></p><figure class="highlight javascript"><table><tr><td class="gutter"><pre>
            <span class="line">1</span>
            <br>
            <span class="line">2</span>
            <br>
            <span class="line">3</span>
            <br>
            <span class="line">4</span>
            <br>
            <span class="line">5</span>
            <br>
          </pre></td><td class="code"><pre>
            <span class="line">
              <span class="comment">// 压缩策略</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// w -&amp;gt; windwow , u -&amp;gt; undefined</span>
            </span>
            <br>
            <span class="line">(
              <span class="function">
                <span class="keyword">function</span>(
                <span class="params">w, u</span>) </span>&#123;</span>
            <br>
            <span class="line"></span>
            <br>
            <span class="line">&#125;)(
              <span class="built_in">window</span>);</span>
            <br>
          </pre></td></tr></table></figure><p></p><h2 id="无-new-构造"><a href="#无-new-构造" class="headerlink" title="无 new 构造"></a>无 new 构造</h2><p>嘿，回想一下使用 jQuery 的时候，实例化一个 jQuery 对象的方法：<br></p><figure class="highlight javascript"><table><tr><td class="gutter"><pre>
            <span class="line">1</span>
            <br>
            <span class="line">2</span>
            <br>
            <span class="line">3</span>
            <br>
            <span class="line">4</span>
            <br>
            <span class="line">5</span>
            <br>
            <span class="line">6</span>
            <br>
          </pre></td><td class="code"><pre>
            <span class="line">
              <span class="comment">// 无 new 构造</span>
            </span>
            <br>
            <span class="line">$(
              <span class="string">'#test'</span>).text(
              <span class="string">'Test'</span>);</span>
            <br>
            <span class="line"></span>
            <br>
            <span class="line">
              <span class="comment">// 当然也可以使用 new</span>
            </span>
            <br>
            <span class="line">
              <span class="keyword">var</span> test =
              <span class="keyword">new</span> $(
              <span class="string">'#test'</span>);</span>
            <br>
            <span class="line">test.text(
              <span class="string">'Test'</span>);</span>
            <br>
          </pre></td></tr></table></figure><p></p><p>大部分人使用 jQuery 的时候都是使用第一种无 new 的构造方式，直接 $(‘’) 进行构造，这也是 jQuery 十分便捷的一个地方。当我们使用第一种无 new 构造方式的时候，其本质就是相当于 new jQuery()，那么在 jQuery 内部是如何实现的呢？看看：<br></p><figure class="highlight javascript"><table><tr><td class="gutter"><pre>
            <span class="line">1</span>
            <br>
            <span class="line">2</span>
            <br>
            <span class="line">3</span>
            <br>
            <span class="line">4</span>
            <br>
            <span class="line">5</span>
            <br>
            <span class="line">6</span>
            <br>
            <span class="line">7</span>
            <br>
            <span class="line">8</span>
            <br>
            <span class="line">9</span>
            <br>
            <span class="line">10</span>
            <br>
            <span class="line">11</span>
            <br>
            <span class="line">12</span>
            <br>
            <span class="line">13</span>
            <br>
            <span class="line">14</span>
            <br>
            <span class="line">15</span>
            <br>
            <span class="line">16</span>
            <br>
            <span class="line">17</span>
            <br>
            <span class="line">18</span>
            <br>
            <span class="line">19</span>
            <br>
            <span class="line">20</span>
            <br>
            <span class="line">21</span>
            <br>
            <span class="line">22</span>
            <br>
            <span class="line">23</span>
            <br>
            <span class="line">24</span>
            <br>
            <span class="line">25</span>
            <br>
          </pre></td><td class="code"><pre>
            <span class="line">(
              <span class="function">
                <span class="keyword">function</span>(
                <span class="params">window, undefined</span>) </span>&#123;</span>
            <br>
            <span class="line">
              <span class="keyword">var</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// ...</span>
            </span>
            <br>
            <span class="line"> jQuery =
              <span class="function">
                <span class="keyword">function</span>(
                <span class="params">selector, context</span>) </span>&#123;</span>
            <br>
            <span class="line">
              <span class="comment">// The jQuery object is actually just the init constructor 'enhanced'</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// 看这里，实例化方法 jQuery() 实际上是调用了其拓展的原型方法 jQuery.fn.init</span>
            </span>
            <br>
            <span class="line">
              <span class="keyword">return</span>
              <span class="keyword">new</span> jQuery.fn.init(selector, context, rootjQuery);</span>
            <br>
            <span class="line"> &#125;,</span>
            <br>
            <span class="line"></span>
            <br>
            <span class="line">
              <span class="comment">// jQuery.prototype 即是 jQuery 的原型，挂载在上面的方法，即可让所有生成的 jQuery 对象使用</span>
            </span>
            <br>
            <span class="line"> jQuery.fn = jQuery.prototype = &#123;</span>
            <br>
            <span class="line">
              <span class="comment">// 实例化化方法，这个方法可以称作 jQuery 对象构造器</span>
            </span>
            <br>
            <span class="line"> init:
              <span class="function">
                <span class="keyword">function</span>(
                <span class="params">selector, context, rootjQuery</span>) </span>&#123;</span>
            <br>
            <span class="line">
              <span class="comment">// ...</span>
            </span>
            <br>
            <span class="line"> &#125;</span>
            <br>
            <span class="line"> &#125;</span>
            <br>
            <span class="line">
              <span class="comment">// 这一句很关键，也很绕</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// jQuery 没有使用 new 运算符将 jQuery 实例化，而是直接调用其函数</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// 要实现这样,那么 jQuery 就要看成一个类，且返回一个正确的实例</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// 且实例还要能正确访问 jQuery 类原型上的属性与方法</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// jQuery 的方式是通过原型传递解决问题，把 jQuery 的原型传递给jQuery.prototype.init.prototype</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// 所以通过这个方法生成的实例 this 所指向的仍然是 jQuery.fn，所以能正确访问 jQuery 类原型上的属性与方法</span>
            </span>
            <br>
            <span class="line"> jQuery.fn.init.prototype = jQuery.fn;</span>
            <br>
            <span class="line"></span>
            <br>
            <span class="line">&#125;)(
              <span class="built_in">window</span>);</span>
            <br>
          </pre></td></tr></table></figure><p></p><p>大部分人初看 jQuery.fn.init.prototype = jQuery.fn 这一句都会被卡主，很是不解。但是这句真的算是 jQuery 的绝妙之处。理解这几句很重要，分点解析一下：</p><ul><li><p>首先要明确，使用 $(‘xxx’) 这种实例化方式，其内部调用的是 return new jQuery.fn.init(selector, context, rootjQuery) 这一句话，也就是构造实例是交给了 jQuery.fn.init() 方法取完成。</p></li><li><p>将 jQuery.fn.init 的 prototype 属性设置为 jQuery.fn，那么使用 new jQuery.fn.init() 生成的对象的原型对象就是 jQuery.fn ，所以挂载到 jQuery.fn 上面的函数就相当于挂载到 jQuery.fn.init() 生成的 jQuery 对象上，所有使用 new jQuery.fn.init() 生成的对象也能够访问到 jQuery.fn 上的所有原型方法。</p></li><li><p>也就是实例化方法存在这么一个关系链</p></li></ul><ul><li>jQuery.fn.init.prototype = jQuery.fn = jQuery.prototype ;</li><li>new jQuery.fn.init() 相当于 new jQuery() ;</li><li>jQuery() 返回的是 new jQuery.fn.init()，而 var obj = new jQuery()，所以这 2 者是相当的，所以我们可以无 new 实例化 jQuery 对象。</li></ul><h2 id="方法的重载"><a href="#方法的重载" class="headerlink" title="方法的重载"></a>方法的重载</h2><p>jQuery 源码晦涩难读的另一个原因是，使用了大量的方法重载，但是用起来却很方便：<br></p><figure class="highlight javascript"><table><tr><td class="gutter"><pre>
            <span class="line">1</span>
            <br>
            <span class="line">2</span>
            <br>
            <span class="line">3</span>
            <br>
            <span class="line">4</span>
            <br>
            <span class="line">5</span>
            <br>
            <span class="line">6</span>
            <br>
            <span class="line">7</span>
            <br>
            <span class="line">8</span>
            <br>
            <span class="line">9</span>
            <br>
          </pre></td><td class="code"><pre>
            <span class="line">
              <span class="comment">// 获取 title 属性的值</span>
            </span>
            <br>
            <span class="line">$(
              <span class="string">'#id'</span>).attr(
              <span class="string">'title'</span>);</span>
            <br>
            <span class="line">
              <span class="comment">// 设置 title 属性的值</span>
            </span>
            <br>
            <span class="line">$(
              <span class="string">'#id'</span>).attr(
              <span class="string">'title'</span>,
              <span class="string">'jQuery'</span>);</span>
            <br>
            <span class="line"></span>
            <br>
            <span class="line">
              <span class="comment">// 获取 css 某个属性的值</span>
            </span>
            <br>
            <span class="line">$(
              <span class="string">'#id'</span>).css(
              <span class="string">'title'</span>);</span>
            <br>
            <span class="line">
              <span class="comment">// 设置 css 某个属性的值</span>
            </span>
            <br>
            <span class="line">$(
              <span class="string">'#id'</span>).css(
              <span class="string">'width'</span>,
              <span class="string">'200px'</span>);</span>
            <br>
          </pre></td></tr></table></figure><p></p><p>方法的重载即是一个方法实现多种功能，经常又是 get 又是 set，虽然阅读起来十分不易，但是从实用性的角度考虑，这也是为什么 jQuery 如此受欢迎的原因，大多数人使用 jQuery() 构造方法使用的最多的就是直接实例化一个 jQuery 对象，但其实在它的内部实现中，有着 9 种不同的方法重载场景：<br></p><figure class="highlight javascript"><table><tr><td class="gutter"><pre>
            <span class="line">1</span>
            <br>
            <span class="line">2</span>
            <br>
            <span class="line">3</span>
            <br>
            <span class="line">4</span>
            <br>
            <span class="line">5</span>
            <br>
            <span class="line">6</span>
            <br>
            <span class="line">7</span>
            <br>
            <span class="line">8</span>
            <br>
            <span class="line">9</span>
            <br>
            <span class="line">10</span>
            <br>
            <span class="line">11</span>
            <br>
            <span class="line">12</span>
            <br>
            <span class="line">13</span>
            <br>
            <span class="line">14</span>
            <br>
            <span class="line">15</span>
            <br>
            <span class="line">16</span>
            <br>
            <span class="line">17</span>
            <br>
          </pre></td><td class="code"><pre>
            <span class="line">
              <span class="comment">// 接受一个字符串，其中包含了用于匹配元素集合的 CSS 选择器</span>
            </span>
            <br>
            <span class="line">jQuery([selector,[context]])</span>
            <br>
            <span class="line">
              <span class="comment">// 传入单个 DOM</span>
            </span>
            <br>
            <span class="line">jQuery(element)</span>
            <br>
            <span class="line">
              <span class="comment">// 传入 DOM 数组</span>
            </span>
            <br>
            <span class="line">jQuery(elementArray)</span>
            <br>
            <span class="line">
              <span class="comment">// 传入 JS 对象</span>
            </span>
            <br>
            <span class="line">jQuery(object)</span>
            <br>
            <span class="line">
              <span class="comment">// 传入 jQuery 对象</span>
            </span>
            <br>
            <span class="line">jQuery(jQuery object)</span>
            <br>
            <span class="line">
              <span class="comment">// 传入原始 HTML 的字符串来创建 DOM 元素</span>
            </span>
            <br>
            <span class="line">jQuery(html,[ownerDocument])</span>
            <br>
            <span class="line">jQuery(html,[attributes])</span>
            <br>
            <span class="line">
              <span class="comment">// 传入空参数</span>
            </span>
            <br>
            <span class="line">jQuery()</span>
            <br>
            <span class="line">
              <span class="comment">// 绑定一个在 DOM 文档载入完成后执行的函数</span>
            </span>
            <br>
            <span class="line">jQuery(callback)</span>
            <br>
          </pre></td></tr></table></figure><p></p><p>所以读源码的时候，很重要的一点是结合 jQuery API 进行阅读，去了解方法重载了多少种功能。</p><p>同时我想说的是，jQuery 源码有些方法的实现特别长且繁琐，因为 jQuery 本身作为一个通用性特别强的框架，一个方法兼容了许多情况，也允许用户传入各种不同的参数，导致内部处理的逻辑十分复杂，所以当解读一个方法的时候感觉到了明显的困难，尝试着跳出卡壳的那段代码本身，站在更高的维度去思考这些复杂的逻辑是为了处理或兼容什么，是否是重载，为什么要这样写，一定会有不一样的收获。</p><p>其次，也是因为这个原因，jQuery 源码存在许多兼容低版本的 HACK 或者逻辑十分晦涩繁琐的代码片段，浏览器兼容这样的大坑极其容易让一个前端工程师不能学到编程的精髓，所以不要太执着于一些边角料，即使兼容性很重要，也应该适度学习理解，适可而止。</p><h2 id="jQuery-fn-extend-与-jQuery-extend"><a href="#jQuery-fn-extend-与-jQuery-extend" class="headerlink" title="jQuery.fn.extend 与 jQuery.extend"></a>jQuery.fn.extend 与 jQuery.extend</h2><p>extend 方法在 jQuery 中是一个很重要的方法，jQuey 内部用它来扩展静态方法或实例方法，而且我们开发 jQuery 插件开发的时候也会用到它。但是在内部，是存在 jQuery.fn.extend 和 jQuery.extend 两个 extend 方法的，而区分这两个 extend 方法是理解 jQuery 的很关键的一部分。先看结论：</p><ul><li><p>jQuery.extend(object) 为扩展 jQuery 类本身，为类添加新的静态方法；</p></li><li><p>jQuery.fn.extend(object) 给 jQuery 对象添加实例方法，也就是通过这个 extend 添加的新方法，实例化的 jQuery 对象都能使用，因为它是挂载在 jQuery.fn 上的方法（上文有提到，jQuery.fn = jQuery.prototype ）。</p></li></ul><p>它们的官方解释是：</p><ul><li><p>jQuery.extend(): 把两个或者更多的对象合并到第一个当中，</p></li><li><p>jQuery.fn.extend()：把对象挂载到 jQuery 的 prototype 属性，来扩展一个新的 jQuery 实例方法。</p></li></ul><p>也就是说，使用 jQuery.extend() 拓展的静态方法，我们可以直接使用 $.xxx 进行调用（xxx是拓展的方法名），</p><p>而使用 jQuery.fn.extend() 拓展的实例方法，需要使用 $().xxx 调用。</p><p>源码解析较长，点击下面可以展开， <a href="https://github.com/chokcoco/jQuery-/blob/master/jquery-1.10.2__read.js" target="_blank" rel="external">也可以去这里阅读</a>：<br></p><figure class="highlight javascript"><table><tr><td class="gutter"><pre>
            <span class="line">1</span>
            <br>
            <span class="line">2</span>
            <br>
            <span class="line">3</span>
            <br>
            <span class="line">4</span>
            <br>
            <span class="line">5</span>
            <br>
            <span class="line">6</span>
            <br>
            <span class="line">7</span>
            <br>
            <span class="line">8</span>
            <br>
            <span class="line">9</span>
            <br>
            <span class="line">10</span>
            <br>
            <span class="line">11</span>
            <br>
            <span class="line">12</span>
            <br>
            <span class="line">13</span>
            <br>
            <span class="line">14</span>
            <br>
            <span class="line">15</span>
            <br>
            <span class="line">16</span>
            <br>
            <span class="line">17</span>
            <br>
            <span class="line">18</span>
            <br>
            <span class="line">19</span>
            <br>
            <span class="line">20</span>
            <br>
            <span class="line">21</span>
            <br>
            <span class="line">22</span>
            <br>
            <span class="line">23</span>
            <br>
            <span class="line">24</span>
            <br>
            <span class="line">25</span>
            <br>
            <span class="line">26</span>
            <br>
            <span class="line">27</span>
            <br>
            <span class="line">28</span>
            <br>
            <span class="line">29</span>
            <br>
            <span class="line">30</span>
            <br>
            <span class="line">31</span>
            <br>
            <span class="line">32</span>
            <br>
            <span class="line">33</span>
            <br>
            <span class="line">34</span>
            <br>
            <span class="line">35</span>
            <br>
            <span class="line">36</span>
            <br>
            <span class="line">37</span>
            <br>
            <span class="line">38</span>
            <br>
            <span class="line">39</span>
            <br>
            <span class="line">40</span>
            <br>
            <span class="line">41</span>
            <br>
            <span class="line">42</span>
            <br>
            <span class="line">43</span>
            <br>
            <span class="line">44</span>
            <br>
            <span class="line">45</span>
            <br>
            <span class="line">46</span>
            <br>
            <span class="line">47</span>
            <br>
            <span class="line">48</span>
            <br>
            <span class="line">49</span>
            <br>
            <span class="line">50</span>
            <br>
            <span class="line">51</span>
            <br>
            <span class="line">52</span>
            <br>
            <span class="line">53</span>
            <br>
            <span class="line">54</span>
            <br>
            <span class="line">55</span>
            <br>
            <span class="line">56</span>
            <br>
            <span class="line">57</span>
            <br>
            <span class="line">58</span>
            <br>
            <span class="line">59</span>
            <br>
            <span class="line">60</span>
            <br>
            <span class="line">61</span>
            <br>
            <span class="line">62</span>
            <br>
            <span class="line">63</span>
            <br>
            <span class="line">64</span>
            <br>
            <span class="line">65</span>
            <br>
            <span class="line">66</span>
            <br>
            <span class="line">67</span>
            <br>
            <span class="line">68</span>
            <br>
            <span class="line">69</span>
            <br>
            <span class="line">70</span>
            <br>
            <span class="line">71</span>
            <br>
            <span class="line">72</span>
            <br>
            <span class="line">73</span>
            <br>
            <span class="line">74</span>
            <br>
            <span class="line">75</span>
            <br>
            <span class="line">76</span>
            <br>
            <span class="line">77</span>
            <br>
            <span class="line">78</span>
            <br>
            <span class="line">79</span>
            <br>
            <span class="line">80</span>
            <br>
            <span class="line">81</span>
            <br>
            <span class="line">82</span>
            <br>
            <span class="line">83</span>
            <br>
            <span class="line">84</span>
            <br>
            <span class="line">85</span>
            <br>
            <span class="line">86</span>
            <br>
            <span class="line">87</span>
            <br>
            <span class="line">88</span>
            <br>
            <span class="line">89</span>
            <br>
            <span class="line">90</span>
            <br>
            <span class="line">91</span>
            <br>
            <span class="line">92</span>
            <br>
            <span class="line">93</span>
            <br>
            <span class="line">94</span>
            <br>
            <span class="line">95</span>
            <br>
            <span class="line">96</span>
            <br>
            <span class="line">97</span>
            <br>
            <span class="line">98</span>
            <br>
            <span class="line">99</span>
            <br>
            <span class="line">100</span>
            <br>
            <span class="line">101</span>
            <br>
            <span class="line">102</span>
            <br>
            <span class="line">103</span>
            <br>
            <span class="line">104</span>
            <br>
            <span class="line">105</span>
            <br>
            <span class="line">106</span>
            <br>
            <span class="line">107</span>
            <br>
            <span class="line">108</span>
            <br>
            <span class="line">109</span>
            <br>
            <span class="line">110</span>
            <br>
          </pre></td><td class="code"><pre>
            <span class="line">
              <span class="comment">// 扩展合并函数</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// 合并两个或更多对象的属性到第一个对象中，jQuery 后续的大部分功能都通过该函数扩展</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// 虽然实现方式一样，但是要注意区分用法的不一样，那么为什么两个方法指向同一个函数实现，但是却实现不同的功能呢,</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// 阅读源码就能发现这归功于 this 的强大力量</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// 如果传入两个或多个对象，所有对象的属性会被添加到第一个对象 target</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// 如果只传入一个对象，则将对象的属性添加到 jQuery 对象中，也就是添加静态方法</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// 用这种方式，我们可以为 jQuery 命名空间增加新的方法，可以用于编写 jQuery 插件</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// 如果不想改变传入的对象，可以传入一个空对象：$.extend(&#123;&#125;, object1, object2);</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// 默认合并操作是不迭代的，即便 target 的某个属性是对象或属性，也会被完全覆盖而不是合并</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// 如果第一个参数是 true，则是深拷贝</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// 从 object 原型继承的属性会被拷贝，值为 undefined 的属性不会被拷贝</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// 因为性能原因，JavaScript 自带类型的属性不会合并</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// 扩展合并函数</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// 合并两个或更多对象的属性到第一个对象中，jQuery 后续的大部分功能都通过该函数扩展</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// 虽然实现方式一样，但是要注意区分用法的不一样，那么为什么两个方法指向同一个函数实现，但是却实现不同的功能呢,</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// 阅读源码就能发现这归功于 this 的强大力量</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// 如果传入两个或多个对象，所有对象的属性会被添加到第一个对象 target</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// 如果只传入一个对象，则将对象的属性添加到 jQuery 对象中，也就是添加静态方法</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// 用这种方式，我们可以为 jQuery 命名空间增加新的方法，可以用于编写 jQuery 插件</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// 如果不想改变传入的对象，可以传入一个空对象：$.extend(&#123;&#125;, object1, object2);</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// 默认合并操作是不迭代的，即便 target 的某个属性是对象或属性，也会被完全覆盖而不是合并</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// 如果第一个参数是 true，则是深拷贝</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// 从 object 原型继承的属性会被拷贝，值为 undefined 的属性不会被拷贝</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// 因为性能原因，JavaScript 自带类型的属性不会合并</span>
            </span>
            <br>
            <span class="line">jQuery.extend = jQuery.fn.extend =
              <span class="function">
                <span class="keyword">function</span>(
                <span class="params"></span>) </span>&#123;</span>
            <br>
            <span class="line">
              <span class="keyword">var</span> src, copyIsArray, copy, name, options, clone,</span>
            <br>
            <span class="line"> target =
              <span class="built_in">arguments</span>[
              <span class="number">0</span>] || &#123;&#125;,</span>
            <br>
            <span class="line"> i =
              <span class="number">1</span>,</span>
            <br>
            <span class="line"> length =
              <span class="built_in">arguments</span>.length,</span>
            <br>
            <span class="line"> deep =
              <span class="literal">false</span>;</span>
            <br>
            <span class="line"></span>
            <br>
            <span class="line">
              <span class="comment">// Handle a deep copy situation</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// target 是传入的第一个参数</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// 如果第一个参数是布尔类型，则表示是否要深递归，</span>
            </span>
            <br>
            <span class="line">
              <span class="keyword">if</span> (
              <span class="keyword">typeof</span> target ===
              <span class="string">"boolean"</span>) &#123;</span>
            <br>
            <span class="line"> deep = target;</span>
            <br>
            <span class="line"> target =
              <span class="built_in">arguments</span>[
              <span class="number">1</span>] || &#123;&#125;;</span>
            <br>
            <span class="line">
              <span class="comment">// skip the boolean and the target</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// 如果传了类型为 boolean 的第一个参数，i 则从 2 开始</span>
            </span>
            <br>
            <span class="line"> i =
              <span class="number">2</span>;</span>
            <br>
            <span class="line"> &#125;</span>
            <br>
            <span class="line"></span>
            <br>
            <span class="line">
              <span class="comment">// Handle case when target is a string or something (possible in deep
                copy)</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// 如果传入的第一个参数是 字符串或者其他</span>
            </span>
            <br>
            <span class="line">
              <span class="keyword">if</span> (
              <span class="keyword">typeof</span> target !==
              <span class="string">"object"</span> &amp;&amp; !jQuery.isFunction(target)) &#123;</span>
            <br>
            <span class="line"> target = &#123;&#125;;</span>
            <br>
            <span class="line"> &#125;</span>
            <br>
            <span class="line"></span>
            <br>
            <span class="line">
              <span class="comment">// extend jQuery itself if only one argument is passed</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// 如果参数的长度为 1 ，表示是 jQuery 静态方法</span>
            </span>
            <br>
            <span class="line">
              <span class="keyword">if</span> (length === i) &#123;</span>
            <br>
            <span class="line"> target =
              <span class="keyword">this</span>;</span>
            <br>
            <span class="line"> --i;</span>
            <br>
            <span class="line"> &#125;</span>
            <br>
            <span class="line"></span>
            <br>
            <span class="line">
              <span class="comment">// 可以传入多个复制源</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// i 是从 1或2 开始的</span>
            </span>
            <br>
            <span class="line">
              <span class="keyword">for</span> (; i &lt; length; i++) &#123;</span>
            <br>
            <span class="line">
              <span class="comment">// Only deal with non-null/undefined values</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// 将每个源的属性全部复制到 target 上</span>
            </span>
            <br>
            <span class="line">
              <span class="keyword">if</span> ((options =
              <span class="built_in">arguments</span>[i]) !=
              <span class="literal">null</span>) &#123;</span>
            <br>
            <span class="line">
              <span class="comment">// Extend the base object</span>
            </span>
            <br>
            <span class="line">
              <span class="keyword">for</span> (name
              <span class="keyword">in</span> options) &#123;</span>
            <br>
            <span class="line">
              <span class="comment">// src 是源（即本身）的值</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// copy 是即将要复制过去的值</span>
            </span>
            <br>
            <span class="line"> src = target[name];</span>
            <br>
            <span class="line"> copy = options[name];</span>
            <br>
            <span class="line"></span>
            <br>
            <span class="line">
              <span class="comment">// Prevent never-ending loop</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// 防止有环，例如 extend(true, target, &#123;'target':target&#125;);</span>
            </span>
            <br>
            <span class="line">
              <span class="keyword">if</span> (target === copy) &#123;</span>
            <br>
            <span class="line">
              <span class="keyword">continue</span>;</span>
            <br>
            <span class="line"> &#125;</span>
            <br>
            <span class="line"></span>
            <br>
            <span class="line">
              <span class="comment">// Recurse if we're merging plain objects or arrays</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// 这里是递归调用，最终都会到下面的 else if 分支</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// jQuery.isPlainObject 用于测试是否为纯粹的对象</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// 纯粹的对象指的是 通过 "&#123;&#125;" 或者 "new Object" 创建的</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// 如果是深复制</span>
            </span>
            <br>
            <span class="line">
              <span class="keyword">if</span> (deep &amp;&amp; copy &amp;&amp; (jQuery.isPlainObject(copy)
              || (copyIsArray = jQuery.isArray(copy)))) &#123;</span>
            <br>
            <span class="line">
              <span class="comment">// 数组</span>
            </span>
            <br>
            <span class="line">
              <span class="keyword">if</span> (copyIsArray) &#123;</span>
            <br>
            <span class="line"> copyIsArray =
              <span class="literal">false</span>;</span>
            <br>
            <span class="line"> clone = src &amp;&amp; jQuery.isArray(src) ? src : [];</span>
            <br>
            <span class="line"></span>
            <br>
            <span class="line">
              <span class="comment">// 对象</span>
            </span>
            <br>
            <span class="line"> &#125;
              <span class="keyword">else</span> &#123;</span>
            <br>
            <span class="line"> clone = src &amp;&amp; jQuery.isPlainObject(src) ? src : &#123;&#125;;</span>
            <br>
            <span class="line"> &#125;</span>
            <br>
            <span class="line"></span>
            <br>
            <span class="line">
              <span class="comment">// Never move original objects, clone them</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// 递归</span>
            </span>
            <br>
            <span class="line"> target[name] = jQuery.extend(deep, clone, copy);</span>
            <br>
            <span class="line"></span>
            <br>
            <span class="line">
              <span class="comment">// Don't bring in undefined values</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// 最终都会到这条分支</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// 简单的值覆盖</span>
            </span>
            <br>
            <span class="line"> &#125;
              <span class="keyword">else</span>
              <span class="keyword">if</span> (copy !==
              <span class="literal">undefined</span>) &#123;</span>
            <br>
            <span class="line"> target[name] = copy;</span>
            <br>
            <span class="line"> &#125;</span>
            <br>
            <span class="line"> &#125;</span>
            <br>
            <span class="line"> &#125;</span>
            <br>
            <span class="line"> &#125;</span>
            <br>
            <span class="line"></span>
            <br>
            <span class="line">
              <span class="comment">// Return the modified object</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// 返回新的 target</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// 如果 i &lt; length ，是直接返回没经过处理的 target，也就是 arguments[0]</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// 也就是如果不传需要覆盖的源，调用 $.extend 其实是增加 jQuery 的静态方法</span>
            </span>
            <br>
            <span class="line">
              <span class="keyword">return</span> target;</span>
            <br>
            <span class="line">&#125;;</span>
            <br>
          </pre></td></tr></table></figure><p></p><p>需要注意的是这一句 jQuery.extend = jQuery.fn.extend = function() {} ，也就是 jQuery.extend 的实现和 jQuery.fn.extend 的实现共用了同一个方法，但是为什么能够实现不同的功能了，这就要归功于 Javascript 强大（怪异？）的 this 了。</p><ul><li><p>在 jQuery.extend() 中，this 的指向是 jQuery 对象(或者说是 jQuery 类)，所以这里扩展在 jQuery 上；</p></li><li><p>在 jQuery.fn.extend() 中，this 的指向是 fn 对象，前面有提到 jQuery.fn = jQuery.prototype ，也就是这里增加的是原型方法，也就是对象方法。</p></li></ul><h2 id="jQuery-的链式调用及回溯"><a href="#jQuery-的链式调用及回溯" class="headerlink" title="jQuery 的链式调用及回溯"></a>jQuery 的链式调用及回溯</h2><p>另一个让大家喜爱使用 jQuery 的原因是它的链式调用，这一点的实现其实很简单，只需要在要实现链式调用的方法的返回结果里，返回 this ，就能够实现链式调用了。</p><p>当然，除了链式调用，jQuery 甚至还允许回溯，看看：<br></p><figure class="highlight javascript"><table><tr><td class="gutter"><pre>
            <span class="line">1</span>
            <br>
            <span class="line">2</span>
            <br>
          </pre></td><td class="code"><pre>
            <span class="line">
              <span class="comment">// 通过 end() 方法终止在当前链的最新过滤操作，返回上一个对象集合</span>
            </span>
            <br>
            <span class="line">$(
              <span class="string">'div'</span>).eq(
              <span class="number">0</span>).show().end().eq(
              <span class="number">1</span>).hide();</span>
            <br>
          </pre></td></tr></table></figure><p></p><p>当选择了 (‘div’).eq(0) 之后使用 end() 可以回溯到上一步选中的 jQuery 对象 $(‘div’)，其内部实现其实是依靠添加了 prevObject 这个属性：</p><p><img src="http://images2015.cnblogs.com/blog/608782/201603/608782-20160314191813506-188474195.jpg" alt=""></p><p>jQuery 完整的链式调用、增栈、回溯通过 return this 、 return this.pushStack() 、return this.prevObject 实现，看看源码实现：<br></p><figure class="highlight javascript"><table><tr><td class="gutter"><pre>
            <span class="line">1</span>
            <br>
            <span class="line">2</span>
            <br>
            <span class="line">3</span>
            <br>
            <span class="line">4</span>
            <br>
            <span class="line">5</span>
            <br>
            <span class="line">6</span>
            <br>
            <span class="line">7</span>
            <br>
            <span class="line">8</span>
            <br>
            <span class="line">9</span>
            <br>
            <span class="line">10</span>
            <br>
            <span class="line">11</span>
            <br>
            <span class="line">12</span>
            <br>
            <span class="line">13</span>
            <br>
            <span class="line">14</span>
            <br>
            <span class="line">15</span>
            <br>
            <span class="line">16</span>
            <br>
            <span class="line">17</span>
            <br>
            <span class="line">18</span>
            <br>
            <span class="line">19</span>
            <br>
            <span class="line">20</span>
            <br>
            <span class="line">21</span>
            <br>
            <span class="line">22</span>
            <br>
            <span class="line">23</span>
            <br>
            <span class="line">24</span>
            <br>
            <span class="line">25</span>
            <br>
            <span class="line">26</span>
            <br>
            <span class="line">27</span>
            <br>
            <span class="line">28</span>
            <br>
            <span class="line">29</span>
            <br>
            <span class="line">30</span>
            <br>
            <span class="line">31</span>
            <br>
            <span class="line">32</span>
            <br>
            <span class="line">33</span>
            <br>
            <span class="line">34</span>
            <br>
            <span class="line">35</span>
            <br>
            <span class="line">36</span>
            <br>
          </pre></td><td class="code"><pre>
            <span class="line">jQuery.fn = jQuery.prototype = &#123;</span>
            <br>
            <span class="line">
              <span class="comment">// 将一个 DOM 元素集合加入到 jQuery 栈</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// 此方法在 jQuery 的 DOM 操作中被频繁的使用, 如在 parent(), find(), filter() 中</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// pushStack() 方法通过改变一个 jQuery 对象的 prevObject 属性来跟踪链式调用中前一个方法返回的 DOM
                结果集合</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// 当我们在链式调用 end() 方法后, 内部就返回当前 jQuery 对象的 prevObject 属性</span>
            </span>
            <br>
            <span class="line"> pushStack:
              <span class="function">
                <span class="keyword">function</span>(
                <span class="params">elems</span>) </span>&#123;</span>
            <br>
            <span class="line">
              <span class="comment">// 构建一个新的jQuery对象，无参的 this.constructor()，只是返回引用this</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// jQuery.merge 把 elems 节点合并到新的 jQuery 对象</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// this.constructor 就是 jQuery 的构造函数 jQuery.fn.init，所以 this.constructor()
                返回一个 jQuery 对象</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// 由于 jQuery.merge 函数返回的对象是第二个函数附加到第一个上面，所以 ret 也是一个 jQuery 对象，这里可以解释为什么
                pushStack 出入的 DOM 对象也可以用 CSS 方法进行操作</span>
            </span>
            <br>
            <span class="line">
              <span class="keyword">var</span> ret = jQuery.merge(
              <span class="keyword">this</span>.constructor(), elems);</span>
            <br>
            <span class="line"></span>
            <br>
            <span class="line">
              <span class="comment">// 给返回的新 jQuery 对象添加属性 prevObject</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// 所以也就是为什么通过 prevObject 能取到上一个合集的引用了</span>
            </span>
            <br>
            <span class="line"> ret.prevObject =
              <span class="keyword">this</span>;</span>
            <br>
            <span class="line"> ret.context =
              <span class="keyword">this</span>.context;</span>
            <br>
            <span class="line"></span>
            <br>
            <span class="line">
              <span class="comment">// Return the newly-formed element set</span>
            </span>
            <br>
            <span class="line">
              <span class="keyword">return</span> ret;</span>
            <br>
            <span class="line"> &#125;,</span>
            <br>
            <span class="line">
              <span class="comment">// 回溯链式调用的上一个对象</span>
            </span>
            <br>
            <span class="line"> end:
              <span class="function">
                <span class="keyword">function</span>(
                <span class="params"></span>) </span>&#123;</span>
            <br>
            <span class="line">
              <span class="comment">// 回溯的关键是返回 prevObject 属性</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// 而 prevObject 属性保存了上一步操作的 jQuery 对象集合</span>
            </span>
            <br>
            <span class="line">
              <span class="keyword">return</span>
              <span class="keyword">this</span>.prevObject ||
              <span class="keyword">this</span>.constructor(
              <span class="literal">null</span>);</span>
            <br>
            <span class="line"> &#125;,</span>
            <br>
            <span class="line">
              <span class="comment">// 取当前 jQuery 对象的第 i 个</span>
            </span>
            <br>
            <span class="line"> eq:
              <span class="function">
                <span class="keyword">function</span>(
                <span class="params">i</span>) </span>&#123;</span>
            <br>
            <span class="line">
              <span class="comment">// jQuery 对象集合的长度</span>
            </span>
            <br>
            <span class="line">
              <span class="keyword">var</span> len =
              <span class="keyword">this</span>.length,</span>
            <br>
            <span class="line"> j = +i + (i &lt;
              <span class="number">0</span> ? len :
              <span class="number">0</span>);</span>
            <br>
            <span class="line"></span>
            <br>
            <span class="line">
              <span class="comment">// 利用 pushStack 返回</span>
            </span>
            <br>
            <span class="line">
              <span class="keyword">return</span>
              <span class="keyword">this</span>.pushStack(j &gt;=
              <span class="number">0</span> &amp;&amp; j &lt; len ? [
              <span class="keyword">this</span>[j]] : []);</span>
            <br>
            <span class="line"> &#125;,</span>
            <br>
            <span class="line">&#125;</span>
            <br>
          </pre></td></tr></table></figure><p></p><p>总的来说，</p><ul><li><p>end() 方法返回 prevObject 属性，这个属性记录了上一步操作的 jQuery 对象合集；</p></li><li><p>而 prevObject 属性由 pushStack() 方法生成，该方法将一个 DOM 元素集合加入到 jQuery 内部管理的一个栈中，通过改变 jQuery 对象的 prevObject 属性来跟踪链式调用中前一个方法返回的 DOM 结果集合</p></li><li><p>当我们在链式调用 end() 方法后，内部就返回当前 jQuery 对象的 prevObject 属性，完成回溯。</p></li></ul><h2 id="正则与细节优化"><a href="#正则与细节优化" class="headerlink" title="正则与细节优化"></a>正则与细节优化</h2><p>不得不提 jQuery 在细节优化上做的很好。也存在很多值得学习的小技巧，下一篇将会以 jQuery 中的一些编程技巧为主题行文，这里就不再赘述。</p><p>然后想谈谈正则表达式，jQuery 当中用了大量的正则表达式，我觉得如果研读 jQuery ，正则水平一定能够大大提升，如果是个正则小白，我建议在阅读之前先去了解以下几点：</p><ul><li><p>了解并尝试使用 Javascript 正则相关 API，包括了 test() 、replace() 、match() 、exec() 的用法；</p></li><li><p>区分上面 4 个方法，哪个是 RegExp 对象方法，哪个是 String 对象方法；</p></li><li><p>了解简单的零宽断言，了解什么是匹配但是不捕获以及匹配并且捕获。</p></li></ul><h2 id="变量冲突处理"><a href="#变量冲突处理" class="headerlink" title="变量冲突处理"></a>变量冲突处理</h2><p>最后想提一提 jQuery 变量的冲突处理，通过一开始保存全局变量的 window.jQuery 以及 windw.$ 。</p><p>当需要处理冲突的时候，调用静态方法 noConflict()，让出变量的控制权，源码如下：<br></p><figure class="highlight javascript"><table><tr><td class="gutter"><pre>
            <span class="line">1</span>
            <br>
            <span class="line">2</span>
            <br>
            <span class="line">3</span>
            <br>
            <span class="line">4</span>
            <br>
            <span class="line">5</span>
            <br>
            <span class="line">6</span>
            <br>
            <span class="line">7</span>
            <br>
            <span class="line">8</span>
            <br>
            <span class="line">9</span>
            <br>
            <span class="line">10</span>
            <br>
            <span class="line">11</span>
            <br>
            <span class="line">12</span>
            <br>
            <span class="line">13</span>
            <br>
            <span class="line">14</span>
            <br>
            <span class="line">15</span>
            <br>
            <span class="line">16</span>
            <br>
            <span class="line">17</span>
            <br>
            <span class="line">18</span>
            <br>
            <span class="line">19</span>
            <br>
            <span class="line">20</span>
            <br>
            <span class="line">21</span>
            <br>
            <span class="line">22</span>
            <br>
            <span class="line">23</span>
            <br>
            <span class="line">24</span>
            <br>
            <span class="line">25</span>
            <br>
            <span class="line">26</span>
            <br>
            <span class="line">27</span>
            <br>
            <span class="line">28</span>
            <br>
            <span class="line">29</span>
            <br>
            <span class="line">30</span>
            <br>
          </pre></td><td class="code"><pre>
            <span class="line">(
              <span class="function">
                <span class="keyword">function</span>(
                <span class="params">window, undefined</span>) </span>&#123;</span>
            <br>
            <span class="line">
              <span class="keyword">var</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// Map over jQuery in case of overwrite</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// 设置别名，通过两个私有变量映射了 window 环境下的 jQuery 和 $ 两个对象，以防止变量被强行覆盖</span>
            </span>
            <br>
            <span class="line"> _jQuery =
              <span class="built_in">window</span>.jQuery,</span>
            <br>
            <span class="line"> _$ =
              <span class="built_in">window</span>.$;</span>
            <br>
            <span class="line"></span>
            <br>
            <span class="line"> jQuery.extend(&#123;</span>
            <br>
            <span class="line">
              <span class="comment">// noConflict() 方法让出变量 $ 的 jQuery 控制权，这样其他脚本就可以使用它了</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// 通过全名替代简写的方式来使用 jQuery</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// deep -- 布尔值，指示是否允许彻底将 jQuery 变量还原(移交 $ 引用的同时是否移交 jQuery 对象本身)</span>
            </span>
            <br>
            <span class="line"> noConflict:
              <span class="function">
                <span class="keyword">function</span>(
                <span class="params">deep</span>) </span>&#123;</span>
            <br>
            <span class="line">
              <span class="comment">// 判断全局 $ 变量是否等于 jQuery 变量</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// 如果等于，则重新还原全局变量 $ 为 jQuery 运行之前的变量（存储在内部变量 _$ 中）</span>
            </span>
            <br>
            <span class="line">
              <span class="keyword">if</span> (
              <span class="built_in">window</span>.$ === jQuery) &#123;</span>
            <br>
            <span class="line">
              <span class="comment">// 此时 jQuery 别名 $ 失效</span>
            </span>
            <br>
            <span class="line">
              <span class="built_in">window</span>.$ = _$;</span>
            <br>
            <span class="line"> &#125;</span>
            <br>
            <span class="line">
              <span class="comment">// 当开启深度冲突处理并且全局变量 jQuery 等于内部 jQuery，则把全局 jQuery 还原成之前的状况</span>
            </span>
            <br>
            <span class="line">
              <span class="keyword">if</span> (deep &amp;amp;
              <span class="built_in">window</span>.jQuery === jQuery) &#123;</span>
            <br>
            <span class="line">
              <span class="comment">// 如果 deep 为 true，此时 jQuery 失效</span>
            </span>
            <br>
            <span class="line">
              <span class="built_in">window</span>.jQuery = _jQuery;</span>
            <br>
            <span class="line"> &#125;</span>
            <br>
            <span class="line"></span>
            <br>
            <span class="line">
              <span class="comment">// 这里返回的是 jQuery 库内部的 jQuery 构造函数（new jQuery.fn.init()）</span>
            </span>
            <br>
            <span class="line">
              <span class="comment">// 像使用 $ 一样尽情使用它吧</span>
            </span>
            <br>
            <span class="line">
              <span class="keyword">return</span> jQuery;</span>
            <br>
            <span class="line"> &#125;</span>
            <br>
            <span class="line"> &#125;)</span>
            <br>
            <span class="line">&#125;(
              <span class="built_in">window</span>)</span>
            <br>
          </pre></td></tr></table></figure><p></p><p>画了一幅简单的流程图帮助理解：</p><p><img src="http://images2015.cnblogs.com/blog/608782/201603/608782-20160314210036021-1888207934.jpg" alt="jQuery冲突处理流程图" title="jQuery冲突处理流程图"></p><p>那么让出了这两个符号之后，是否就不能在我们的代码中使用 jQuery 或者呢 $ 呢？莫慌，还是可以使用的：<br></p><figure class="highlight javascript"><table><tr><td class="gutter"><pre>
            <span class="line">1</span>
            <br>
            <span class="line">2</span>
            <br>
            <span class="line">3</span>
            <br>
            <span class="line">4</span>
            <br>
            <span class="line">5</span>
            <br>
            <span class="line">6</span>
            <br>
            <span class="line">7</span>
            <br>
            <span class="line">8</span>
            <br>
            <span class="line">9</span>
            <br>
          </pre></td><td class="code"><pre>
            <span class="line">
              <span class="comment">// 让出 jQuery 、$ 的控制权不代表不能使用 jQuery 和 $ ，方法如下：</span>
            </span>
            <br>
            <span class="line">
              <span class="keyword">var</span> query = jQuery.noConflict(
              <span class="literal">true</span>);</span>
            <br>
            <span class="line"></span>
            <br>
            <span class="line">(
              <span class="function">
                <span class="keyword">function</span>(
                <span class="params">$</span>) </span>&#123;</span>
            <br>
            <span class="line"></span>
            <br>
            <span class="line">
              <span class="comment">// 插件或其他形式的代码，也可以将参数设为 jQuery</span>
            </span>
            <br>
            <span class="line">&#125;)(query);</span>
            <br>
            <span class="line"></span>
            <br>
            <span class="line">
              <span class="comment">// ... 其他用 $ 作为别名的库的代码</span>
            </span>
            <br>
          </pre></td></tr></table></figure><p></p><h2 id="结束语"><a href="#结束语" class="headerlink" title="结束语"></a>结束语</h2><p>对 jQuery 整体架构的一些解析就到这里，下一篇将会剖析一下 jQuery 中的一些优化小技巧，一些对编程有所提高的地方。</p><p>原创文章，文笔有限，才疏学浅，文中若有不正之处，万望告知。</p><p>系列第二篇： <a href="http://www.cnblogs.com/coco1s/p/5303041.html" target="_blank" rel="external">【深入浅出jQuery】源码浅析2–奇技淫巧</a></p><p>最后，我在 github 上关于 jQuery 源码的全文注解，感兴趣的可以围观一下，给颗星星。 <a href="https://github.com/chokcoco/jQuery-" target="_blank" rel="external">jQuery v1.10.2 源码注解 </a>。</p>
  </section>

  
  

</article>


<!-- 多说评论框 start -->
  <div class="ds-thread" data-thread-key="post-jQ1" data-title="【深入浅出jQuery】源码浅析--整体架构" data-url="http://sbco.cc/2016/03/14/jQ1/"></div>
<!-- 多说评论框 end -->


        <footer class="footer">
	<div class="friendLink">友情链接：
		<ul>
			<li><a href="http://www.cnblogs.com/coco1s/">Coco</a></li>
			<li><a href="http://www.chengfeilong.com/">Scott's Blog</a></li>
			<li><a href="http://www.52cik.com/">楼教主</a></li>
			<li><a href="http://blog.aisuso.com/">姚嘉鑫博客</a></li>
		</ul>
	</div>
	<div class="copy_right"> &copy; chokcoco </div>
	<span class="footer__copyright"> 2014-2016. | 由<a href="https://hexo.io/"> Hexo </a>强力驱动 | 主题<a href="https://github.com/someus/huno"> Huno </a></span>

</footer>
<!-- 多说公共JS代码 start -->
<script type="text/javascript">
var duoshuoQuery = {short_name:"sbco"};
	(function() {
		var ds = document.createElement('script');
		ds.type = 'text/javascript';ds.async = true;
		ds.src = (document.location.protocol == 'https:' ? 'https:' : 'http:') + '//static.duoshuo.com/embed.js';
		ds.charset = 'UTF-8';
		(document.getElementsByTagName('head')[0]
		 || document.getElementsByTagName('body')[0]).appendChild(ds);
	})();
</script>
<!-- 多说公共JS代码 end -->
<!-- cnzz统计 -->
<script type="text/javascript">
	var cnzz_protocol = (("https:" == document.location.protocol) ? " https://" : " http://");
	document.write(unescape("%3Cspan id='cnzz_stat_icon_1259441963'%3E%3C/span%3E%3Cscript src='" + cnzz_protocol + "s4.cnzz.com/z_stat.php%3Fid%3D1259441963' type='text/javascript'%3E%3C/script%3E"));
</script>
<!-- 文章阅读数统计 -->
<script async src="https://dn-lbstatics.qbox.me/busuanzi/2.3/busuanzi.pure.mini.js"></script>
<!-- 百度爬虫推送 -->
<script>
(function(){
    var bp = document.createElement('script');
    var curProtocol = window.location.protocol.split(':')[0];
    if (curProtocol === 'https') {
        bp.src = 'https://zz.bdstatic.com/linksubmit/push.js';
    }
    else {
        bp.src = 'http://push.zhanzhang.baidu.com/push.js';
    }
    var s = document.getElementsByTagName("script")[0];
    s.parentNode.insertBefore(bp, s);
})();
</script>

      </div>
    </div>
    <!-- js files -->
    <script src="/js/jquery.min.js"></script>
    <script src="/js/main.js"></script>
    <script src="/js/scale.fix.js"></script>
    
    

    <script type="text/javascript" src="//cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
    <script type="text/javascript"> 
        $(document).ready(function(){
            MathJax.Hub.Config({ 
                tex2jax: {inlineMath: [['[latex]','[/latex]'], ['\\(','\\)']]} 
            });
        });
    </script>


    

    <script src="/js/awesome-toc.min.js"></script>
    <script>
        $(document).ready(function(){
            $.awesome_toc({
                overlay: true,
                contentId: "post-content",
            });
        });
    </script>


    
    
    <!--kill ie6 -->
<!--[if IE 6]>
  <script src="//letskillie6.googlecode.com/svn/trunk/2/zh_CN.js"></script>
<![endif]-->
</body>
</html>
